package org.dromara.generator.domain;

import com.baomidou.mybatisplus.annotation.FieldStrategy;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.ibatis.type.JdbcType;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.domain.BaseEntity;


/**
 * @Author 刘武贵
 * @Date 2024/8/15 22:00
 * @Description 功能描述：代码生成业务字段表 gen_table_column
 */
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("gen_table_column")
public class GenTableColumn extends BaseEntity {

    /**
     * 编号
     */
    @TableId(value = "column_id")
    private Long columnId;

    /**
     * 归属表编号
     */
    private Long tableId;

    /**
     * 列名称
     */
    private String columnName;

    /**
     * 列描述
     */
    @TableField(updateStrategy = FieldStrategy.ALWAYS, jdbcType = JdbcType.VARCHAR)
    private String columnComment;

    /**
     * 列类型
     */
    private String columnType;

    /**
     * JAVA类型
     */
    private String javaType;

    /**
     * JAVA字段名
     */
    @NotBlank(message = "Java属性不能为空")
    private String javaField;

    /**
     * 是否主键（1是）
     */
    @TableField(updateStrategy = FieldStrategy.ALWAYS, jdbcType = JdbcType.VARCHAR)
    private String isPk;

    /**
     * 是否自增（1是）
     */
    @TableField(updateStrategy = FieldStrategy.ALWAYS, jdbcType = JdbcType.VARCHAR)
    private String isIncrement;

    /**
     * 是否必填（1是）
     */
    @TableField(updateStrategy = FieldStrategy.ALWAYS, jdbcType = JdbcType.VARCHAR)
    private String isRequired;

    /**
     * 是否为插入字段（1是）
     */
    @TableField(updateStrategy = FieldStrategy.ALWAYS, jdbcType = JdbcType.VARCHAR)
    private String isInsert;

    /**
     * 是否编辑字段（1是）
     */
    @TableField(updateStrategy = FieldStrategy.ALWAYS, jdbcType = JdbcType.VARCHAR)
    private String isEdit;

    /**
     * 是否列表字段（1是）
     */
    @TableField(updateStrategy = FieldStrategy.ALWAYS, jdbcType = JdbcType.VARCHAR)
    private String isList;

    /**
     * 是否查询字段（1是）
     */
    @TableField(updateStrategy = FieldStrategy.ALWAYS, jdbcType = JdbcType.VARCHAR)
    private String isQuery;

    /**
     * 查询方式（EQ等于、NE不等于、GT大于、LT小于、LIKE模糊、BETWEEN范围）
     */
    private String queryType;

    /**
     * 显示类型（input文本框、textarea文本域、select下拉框、checkbox复选框、radio单选框、datetime日期控件、image图片上传控件、upload文件上传控件、editor富文本控件）
     */
    private String htmlType;

    /**
     * 字典类型
     */
    private String dictType;

    /**
     * 排序
     */
    private Integer sort;

    /**
     * 获取Java字段的首字母大写形式
     *
     * @return Java字段的首字母大写形式字符串
     */
    public String getCapJavaField() {
        return StringUtils.capitalize(javaField);
    }

    /**
     * 检查当前对象是否为主键对象
     *
     * @return 如果当前对象为主键对象，则返回true；否则返回false
     */
    public boolean isPk() {
        return isPk(this.isPk);
    }

    /**
     * 检查字段是否为主键
     * <p>
     * 该方法用于判断给定的字符串是否表示一个字段是主键（PK）该判断基于字符串的值是否为"1"
     * 主键在一个数据库表中是唯一的，用于标识一条记录本方法在数据库操作或数据验证时可能被使用
     *
     * @param isPk 待检查的字符串，预期为表示是否为主键的标识符
     * @return 如果字段为主键，返回true；否则返回false
     */
    public boolean isPk(String isPk) {
        // 判断isPk是否非空且等于字符串"1"，是则返回true，表示该字段为主键
        return isPk != null && StringUtils.equals("1", isPk);
    }

    /**
     * 检查是否允许增量操作
     *
     * 此方法用作判断当前情况下是否支持或允许进行增量操作它通过调用
     * isIncrement方法，并将自身的isIncrement字段作为参数传递，以获取是否增量的操作的判断结果
     *
     * @return boolean 返回是否允许增量操作的结果
     */
    public boolean isIncrement() {
        return isIncrement(this.isIncrement);
    }

    /**
     * 判断配置字符串是否表示增量操作
     *
     * 此方法用于解析传入的字符串配置，判断是否设置了增量操作此方法只识别字符串"1"作为增量操作的标识，
     * 其他任何值（包括空字符串或null）都将被视为非增量操作
     *
     * @param isIncrement 字符串，用于表示是否为增量操作根据配置的字符串值判断增量操作的状态
     * @return boolean 表示如果isIncrement为非null且等于字符串"1"，返回true，表示是增量操作；
     *         否则返回false，表示不是增量操作
     */
    public boolean isIncrement(String isIncrement) {
        return isIncrement != null && StringUtils.equals("1", isIncrement);
    }

    /**
     * 判断字段是否是必填项
     *
     * @return 如果字段被标记为必填，则返回true；否则返回false
     */
    public boolean isRequired() {
        return isRequired(this.isRequired);
    }

    /**
     * 判断某个功能是否是必填项
     *
     * @param isRequired 字符串形式的标识符，用于表示是否为必填项
     * @return 如果isRequired非空且等于"1"，则返回true，表示是必填项；否则返回false
     */
    public boolean isRequired(String isRequired) {
        return isRequired != null && StringUtils.equals("1", isRequired);
    }

    /**
     * 判断当前对象是否为插入操作
     *
     * @return 返回一个布尔值，true表示当前操作为插入，false表示非插入
     */
    public boolean isInsert() {
        return isInsert(this.isInsert);
    }

    /**
     * 检查是否进行插入操作
     *
     * @param isInsert 插入操作的标志，通常来源于用户请求或配置信息
     * @return 如果插入标志非空且等于"1"，则返回true，表示需要进行插入操作；否则返回false
     *
     * 此方法用于判断是否满足执行插入操作的条件 主要用于根据用户请求或配置决定是否执行插入操作
     * 使用StringUtils.equals方法进行字符串比较，以避免潜在的NullPointerException
     */
    public boolean isInsert(String isInsert) {
        return isInsert != null && StringUtils.equals("1", isInsert);
    }

    /**
     * 判断当前操作是否为编辑模式
     *
     * 此方法通过调用isInsert方法来判断当前操作是否为编辑模式
     * isEdit的具体判断逻辑被封装在isInsert方法中
     *
     * @return 返回true表示当前操作为编辑模式，否则返回false
     */
    public boolean isEdit() {
        return isInsert(this.isEdit);
    }

    /**
     * 检查是否进行编辑操作
     * <p>
     * 该方法用于判断传入的字符串是否表示进行编辑操作编辑操作的判断条件是字符串不为空且等于"1"
     * </p>
     *
     * @param isEdit 表示是否进行编辑操作的字符串标志
     * @return 如果字符串不为空且等于"1"，返回true，表示进行编辑操作；否则返回false
     */
    public boolean isEdit(String isEdit) {
        return isEdit != null && StringUtils.equals("1", isEdit);
    }

    /**
     * 判断当前对象是否为列表类型
     *
     * 此方法通过委托给私有的布尔变量isList来实现对对象类型判断的功能如果对象是列表类型，
     * 则返回true；否则返回false此方法的存在是为了提供一个公共访问点，以便外部代码可以
     * 安全地查询对象的类型，而无需直接访问内部状态
     *
     * @return boolean 始终返回true如果当前对象是列表类型；否则返回false
     */
    public boolean isList() {
        return isList(this.isList);
    }

    /**
     * 检查给定的字符串是否表示一个列表
     *
     * @param isList 待检查的字符串，通常用于表示是否为列表的标志
     * @return 如果给定字符串等于"1"，则返回true，表示是一个列表；否则返回false
     *
     * 注释：此方法用于判断传入的字符串是否等于"1"。在实际应用中，这种做法可能用于判断某个配置或状态
     * 是否为预设的"列表"模式。选择使用字符串"1"作为判断标准而不是布尔值或其他类型，可能是出于特定的业务需求
     * 或是为了保持接口的一致性和简洁性。
     */
    public boolean isList(String isList) {
        return isList != null && StringUtils.equals("1", isList);
    }

    /**
     * 检查当前对象是否为查询对象
     *
     * @return 当前对象是否为查询对象
     */
    public boolean isQuery() {
        return isQuery(this.isQuery);
    }

    /**
     * 判断查询标志是否为指定的字符串
     *
     * @param isQuery 查询标志字符串，预期为"1"表示真
     * @return 如果查询标志非空且等于"1"，则返回true，否则返回false
     */
    public boolean isQuery(String isQuery) {
        return isQuery != null && StringUtils.equals("1", isQuery);
    }

    /**
     * 判断当前字段是否为超级列
     * <p>
     * 在某些数据库系统中，超级列是一种特殊的数据结构，它能够包含其他列家族或者超级列
     * 这个方法主要用于确定Java字段是否映射到了这样一个特殊的数据库结构
     *
     * @return 如果字段映射到超级列，则返回true；否则返回false
     */
    public boolean isSuperColumn() {
        // 调用重载的isSuperColumn方法，传递Java字段作为参数
        // 这里的this.javaField表示当前实例的Java字段
        return isSuperColumn(this.javaField);
    }

    /**
     * 判断给定的Java字段是否为超级列
     * 超级列是指在多个实体类中重复使用的字段，例如创建者、创建时间、修改者和修改时间，
     * 以及在树形结构实体中使用的父节点名称和父节点ID
     *
     * @param javaField 待检查的Java字段名
     * @return 如果字段名（忽略大小写）与预定义的超级列匹配，则返回true，否则返回false
     */
    public static boolean isSuperColumn(String javaField) {
        // 定义超级列列表，包括BaseEntity和TreeEntity中使用的列
        return StringUtils.equalsAnyIgnoreCase(javaField,
            // BaseEntity中定义的基本超级列，用于跟踪实体的创建和更新信息
            "createBy", "createTime", "updateBy", "updateTime",
            // TreeEntity中定义的用于表示树形结构的超级列
            "parentName", "parentId");
    }

    /**
     * 判断当前列是否可用
     *
     * 本方法用于确定当前操作的列是否满足使用的条件，这一判断对于数据处理或者界面展示中决定哪些列可以被使用（例如显示、搜索等操作）非常重要
     * 它调用了重载的方法 isUsableColumn(javaField)，其中 javaField 应该是一个代表字段的变量，用于判断该字段对应的列是否可用
     *
     * @return 如果列可用，则返回 true；否则返回 false
     */
    public boolean isUsableColumn() {
        return isUsableColumn(javaField);
    }

    /**
     * 判断一个字段是否为可使用的列
     * 此方法用于确定在生成Domain属性时哪些字段是可用的，以避免生成过多不必要的属性
     * 可用列的判断基于一些预定义的字段名，这些字段名在生成页面时可能会被需要
     *
     * @param javaField 字段名，用于检查该字段是否为可使用的列
     * @return boolean 表示字段是否为可使用的列
     */
    public static boolean isUsableColumn(String javaField) {
        // isSuperColumn()中的名单用于避免生成多余Domain属性，若某些属性在生成页面时需要用到不能忽略，则放在此处白名单
        return StringUtils.equalsAnyIgnoreCase(javaField, "parentId", "orderNum", "remark");
    }

    /**
     * 读取并转换备注中的数据表达式
     * 该方法主要用于解析并重组列评论中的数据表达式，以便于后续的处理和使用
     * 表达式的格式从列评论中提取，并转换为“首字母=剩余部分”的形式
     * 例如，如果列评论为“（ A = 1 ）”，则转换后为“A=1”
     *
     * @return 转换后的数据表达式字符串如果列评论为空，则返回原始列评论
     */
    public String readConverterExp() {
        // 提取列评论中的备注部分
        String remarks = StringUtils.substringBetween(this.columnComment, "（", "）");
        StringBuffer sb = new StringBuffer();
        if (StringUtils.isNotEmpty(remarks)) {
            // 遍历备注，转换每个单词为“首字母=剩余部分”的格式
            for (String value : remarks.split(" ")) {
                if (StringUtils.isNotEmpty(value)) {
                    Object startStr = value.subSequence(0, 1);
                    String endStr = value.substring(1);
                    // 追加转换后的表达式到StringBuffer
                    sb.append(StringUtils.EMPTY).append(startStr).append("=").append(endStr).append(StringUtils.SEPARATOR);
                }
            }
            // 删除最后一个多余的分隔符后返回转换后的表达式
            return sb.deleteCharAt(sb.length() - 1).toString();
        } else {
            // 如果备注为空，返回原始列评论
            return this.columnComment;
        }
    }
}
